﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using KC.Framework.Util;
using KC.Framework.Extension;
using KC.Framework.Tenant;
using KC.Model.Storage.Base;
using KC.Model.Storage.Table;
using KC.Service.Storage.Core;
using KC.Storage.Core.Repository.Table;

namespace KC.Service.Storage
{
    public interface IThreadService : IStorageServiceBase
    {
        ThreadConfigInfo GetWorkerRoleConfigToRun(string workerRoleId, string hostName);
        void DeleteWorkerRoleConfigInfo(string rowKey);
        void DeleteUselessWorkerRoleConfig();
        void DeleteAllWorkerRoleConfig();


        List<ThreadStatusInfo> GetThreadStatus();
        void InitializeWorkerRoleThreadStatus(string workerRoleId, string threadname);
        void UpdateWorkerRoleDate(string workerRoleId);
        void UpdateWorkerRoleThreadStatus(string workerRoleId, string threadname, int successCount, int failCount);
        void ResetAllWorkerRoleThreadStatus();
    }

    public interface INoSqlService : IThreadService
    {
        int GetCurrentVersion(string databaseName);
        void UpdateDatabaseStatus(string databaseName, DatabaseStatus status);
        void UpdateDatabaseVersion(string databaseName, int versionNumber);
        bool IsUpgrading(string databaseName);

        #region QueueErrorMessage
        bool AddQueueErrorMessage(QueueErrorMessage model);
        List<QueueErrorMessage> GetAllQueueErrorMessages();
        QueueErrorMessage GetQueueErrorMessage(string rowKey);
        bool RemoveByRowKey(string rowKey);
        PaginatedBase<QueueErrorMessage> FindPagenatedQueueErrorList(int pageIndex,
            int pageSize, string queueName, string sort, string order);
        bool ClearAllQueueErrorMessages();
        #endregion

        #region NLog Table
        List<NLogEntity> GetNLogInfosByTableName(NLogTableType tableName);
        PaginatedBase<NLogEntity> GetNLogInfosByTableNameAndPage(NLogTableType tableName, int pageIndex,
            int pageSize, string logLevel);
        NLogEntity GetNLogDetail(NLogTableType tableName, string rowKey);
        bool ClearAllNlogByTableName(NLogTableType tableName);
        bool DeleteNLog(NLogTableType tableName, string rowKey);
        #endregion
    }

    public class NoSqlService : StorageServiceBase, INoSqlService
    {
        private const string ServiceName = "KC.Service.Storage.AzureTableService";
        protected DatabaseVersionInfoDataContext DatabaseVersionInfoRepository { get; set; }
        protected QueueErrorMessageDataContext QueueErrorMessageRepository { get; set; }
        protected ThreadConfigInfoDataContext ThreadConfigInfoRepository { get; set; }
        protected ThreadStatusInfoDataContext ThreadStatusInfoRepository { get; set; }

        public NoSqlService()
        {
            var storageType = KC.Framework.Base.GlobalConfig.BlobStorage.ToLower();
            switch (storageType)
            {
                case "filesystem":
                    {
                        DatabaseVersionInfoRepository = new DatabaseVersionInfoDataContext();
                        QueueErrorMessageRepository = new QueueErrorMessageDataContext();
                        ThreadConfigInfoRepository = new ThreadConfigInfoDataContext();
                        ThreadStatusInfoRepository = new ThreadStatusInfoDataContext();
                    }
                    break;
                case "azure":
                    {
                        DatabaseVersionInfoRepository = new DatabaseVersionInfoDataContext();
                        QueueErrorMessageRepository = new QueueErrorMessageDataContext();
                        ThreadConfigInfoRepository = new ThreadConfigInfoDataContext();
                        ThreadStatusInfoRepository = new ThreadStatusInfoDataContext();
                    }
                    break;
                case "cmb":
                    {
                        DatabaseVersionInfoRepository = new DatabaseVersionInfoDataContext();
                        QueueErrorMessageRepository = new QueueErrorMessageDataContext();
                        ThreadConfigInfoRepository = new ThreadConfigInfoDataContext();
                        ThreadStatusInfoRepository = new ThreadStatusInfoDataContext();
                    }
                    break;
                default:
                    {
                        DatabaseVersionInfoRepository = new DatabaseVersionInfoDataContext();
                        QueueErrorMessageRepository = new QueueErrorMessageDataContext();
                        ThreadConfigInfoRepository = new ThreadConfigInfoDataContext();
                        ThreadStatusInfoRepository = new ThreadStatusInfoDataContext();
                    }
                    break;
            }
        }

        public NoSqlService(Tenant tenant)
        {
            Tenant = tenant;
            var nosqlType = tenant.NoSqlType;
            switch (nosqlType)
            {
                case NoSqlType.AzureTable:
                    DatabaseVersionInfoRepository = new DatabaseVersionInfoDataContext(tenant);
                    QueueErrorMessageRepository = new QueueErrorMessageDataContext(tenant);
                    ThreadConfigInfoRepository = new ThreadConfigInfoDataContext(tenant);
                    ThreadStatusInfoRepository = new ThreadStatusInfoDataContext(tenant);
                    break;
                default:
                    DatabaseVersionInfoRepository = new DatabaseVersionInfoDataContext(tenant);
                    QueueErrorMessageRepository = new QueueErrorMessageDataContext(tenant);
                    ThreadConfigInfoRepository = new ThreadConfigInfoDataContext(tenant);
                    ThreadStatusInfoRepository = new ThreadStatusInfoDataContext(tenant);
                    break;
            }
        }

        #region DatabaseVersionInfo

        public int GetCurrentVersion(string databaseName)
        {
            try
            {
                return DatabaseVersionInfoRepository.GetCurrentVersion(databaseName);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return 0;
            }
        }

        public void UpdateDatabaseStatus(string databaseName, DatabaseStatus status)
        {
            try
            {
                DatabaseVersionInfoRepository.UpdateDatabaseStatus(databaseName, status);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
            }
        }

        public void UpdateDatabaseVersion(string databaseName, int versionNumber)
        {
            try
            {
                DatabaseVersionInfoRepository.UpdateDatabaseVersion(databaseName, versionNumber);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
            }
        }

        public bool IsUpgrading(string databaseName)
        {
            try
            {
                return DatabaseVersionInfoRepository.IsUpgrading(databaseName);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return false;
            }
        }

        #endregion

        #region QueueErrorMessage

        public bool AddQueueErrorMessage(QueueErrorMessage model)
        {
            try
            {
                return QueueErrorMessageRepository.Add(model);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return false;
            }
        }

        public List<QueueErrorMessage> GetAllQueueErrorMessages()
        {
            try
            {
                return QueueErrorMessageRepository.FindAll().ToList();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }

        public bool RemoveByRowKey(string rowKey)
        {
            try
            {
                return QueueErrorMessageRepository.RemoveByRowKey(rowKey);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return false;
            }
        }
        public PaginatedBase<QueueErrorMessage> FindPagenatedQueueErrorList(int pageIndex, int pageSize, string queueName, string sort, string order)
        {
            try
            {
                Expression<Func<QueueErrorMessage, bool>> predicate = m => true;
                if (queueName != null && !queueName.Trim().Equals(string.Empty) && !queueName.Equals("全部"))
                {
                    predicate = predicate.And(m => m.QueueName.ToLower() == queueName.ToLower());
                }
                var data = QueueErrorMessageRepository.FindPagenatedListWithCount(pageIndex, pageSize, predicate, sort, order.Equals("asc"));
                var total = data.Item1;
                var rows = data.Item2.ToList();
                return new PaginatedBase<QueueErrorMessage>(pageIndex, pageSize, total, rows);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }

        public QueueErrorMessage GetQueueErrorMessage(string rowKey)
        {
            try
            {
                return QueueErrorMessageRepository.FindByRowKey(rowKey);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }

        public bool ClearAllQueueErrorMessages()
        {
            try
            {
                return QueueErrorMessageRepository.RemoveAll();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return false;
            }
        }

        #endregion

        #region Thread

        public ThreadConfigInfo GetWorkerRoleConfigToRun(string workerRoleId, string hostName)
        {
            try
            {
                return ThreadConfigInfoRepository.GetWorkerRoleConfigToRun(workerRoleId, hostName);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }

        public void DeleteWorkerRoleConfigInfo(string rowKey)
        {
            try
            {
                ThreadConfigInfoRepository.DeleteWorkerRoleConfigInfo(rowKey);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
            }
        }

        public void DeleteUselessWorkerRoleConfig()
        {
            try
            {
                ThreadConfigInfoRepository.DeleteUselessWorkerRoleConfig();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
            }
        }

        public void DeleteAllWorkerRoleConfig()
        {
            try
            {
                ThreadConfigInfoRepository.DeleteAllWorkerRoleConfig();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
            }
        }

        public List<ThreadStatusInfo> GetThreadStatus()
        {
            try
            {
                return ThreadStatusInfoRepository.GetThreadStatus();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }

        public void InitializeWorkerRoleThreadStatus(string workerRoleId, string threadname)
        {
            try
            {
                ThreadStatusInfoRepository.InitializeWorkerRoleThreadStatus(workerRoleId, threadname);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
            }
        }

        public void UpdateWorkerRoleDate(string workerRoleId)
        {
            try
            {
                ThreadStatusInfoRepository.UpdateWorkerRoleDate(workerRoleId);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
            }
        }

        public void UpdateWorkerRoleThreadStatus(string workerRoleId, string threadname, int successCount, int failCount)
        {
            try
            {
                ThreadStatusInfoRepository.UpdateWorkerRoleThreadStatus(workerRoleId, threadname, successCount, failCount);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
            }
        }

        public void ResetAllWorkerRoleThreadStatus()
        {
            try
            {
                ThreadStatusInfoRepository.ResetAllWorkerRoleThreadStatus();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
            }
        }

        #endregion

        #region Nlog table

        public virtual List<NLogEntity> GetNLogInfosByTableName(NLogTableType tableName)
        {
            try
            {
                var nlogEntityRepository = new NLogEntityDataContext(tableName.ToString());
                return nlogEntityRepository.FindAll().ToList();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }
        //根据条件查询相应的数据
        public PaginatedBase<NLogEntity> GetNLogInfosByTableNameAndPage(NLogTableType tableName, int pageIndex, int pageSize, string logLevel)
        {
            try
            {
                Expression<Func<NLogEntity, bool>> predicate = m => true;
                if (!logLevel.Equals("全部") && !logLevel.Trim().Equals(string.Empty))
                {
                    predicate = predicate.And(m => m.Level.ToLower() == logLevel.ToLower());
                }
                var nlogEntityRepository = new NLogEntityDataContext(tableName.ToString());
                var data = nlogEntityRepository.FindPagenatedListWithCount(pageIndex, pageSize, predicate, "Timestamp",
                    false);
                var total = data.Item1;
                var rows = data.Item2.ToList();
                return new PaginatedBase<NLogEntity>(pageIndex, pageSize, total, rows);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }
        //根据字段判断删除单条日志还是清空日志
        public bool DeleteNLog(NLogTableType tableName, string rowKey)
        {
            try
            {
                var nlogEntityRepository = new NLogEntityDataContext(tableName.ToString());
                if (rowKey == string.Empty)
                {
                    return nlogEntityRepository.RemoveAll();
                }
                else
                {
                    return nlogEntityRepository.RemoveByRowKey(rowKey);
                }
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return false;
            }
        }
        public virtual NLogEntity GetNLogDetail(NLogTableType tableName, string rowKey)
        {
            try
            {
                var nlogEntityRepository = new NLogEntityDataContext(tableName.ToString());
                return nlogEntityRepository.FindByRowKey(rowKey);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }
        public virtual bool ClearAllNlogByTableName(NLogTableType tableName)
        {
            try
            {
                var nlogEntityRepository = new NLogEntityDataContext(tableName.ToString());
                return nlogEntityRepository.RemoveAll();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return false;
            }
        }

        #endregion

    }

    public class TenantNoSqlService : NoSqlService
    {
        private const string ServiceName = "KC.Service.Storage.TenantAzureTableService";
        public TenantNoSqlService(Tenant tenant)
            : base(tenant)
        {
        }

        #region NLog Table
        public override List<NLogEntity> GetNLogInfosByTableName(NLogTableType tableName)
        {
            try
            {
                var nlogEntityRepository = new NLogEntityDataContext(base.Tenant, tableName.ToString());
                return nlogEntityRepository.FindAll().ToList();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }

        public override NLogEntity GetNLogDetail(NLogTableType tableName, string rowKey)
        {
            try
            {
                var nlogEntityRepository = new NLogEntityDataContext(base.Tenant, tableName.ToString());
                return nlogEntityRepository.FindByRowKey(rowKey);
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return null;
            }
        }

        public override bool ClearAllNlogByTableName(NLogTableType tableName)
        {
            try
            {
                var nlogEntityRepository = new NLogEntityDataContext(base.Tenant, tableName.ToString());
                return nlogEntityRepository.RemoveAll();
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ServiceName + " throw exception: " + ex.Message, ex.StackTrace);
                return false;
            }
        }
        #endregion
    }
}
